package com.bid.base.common.util;


import com.bid.base.common.entity.WechatUsers;
import com.bid.base.common.util.auth.AuthAssistant;
import io.jsonwebtoken.*;
import org.codehaus.jackson.map.ObjectMapper;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <strong>Description : </strong> <br>
 * <p>
 * <strong>北京正源德标科技信息有限责任公司</strong> <br>
 * </p>
 * <br>
 *https://www.cnblogs.com/pxblog/p/12954756.html
 * @author : zhaots
 * @date Date : 2020年12月22日 16:13
 * 修改人 修改日期 修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 */
public class JWTUtils {
    public static String ENTITY_KEY= "ENTITY_KEY";

    //服务器的kye.用户做加解密的key数据。
    private static final String defaultJwtSecert = "jwt_secert_zydb@123optv.wefdifjhdi.itrehi";

    private static final ObjectMapper MAPPER = new ObjectMapper();

    public static SecretKey generalKey() {
        return generalKey(null);
    }
    public static SecretKey generalKey(String jwtSecert) {
        try {
            if(null == jwtSecert){
                jwtSecert = defaultJwtSecert;
            }
            byte[] encodedKey = jwtSecert.getBytes("UTF-8");
            SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
            return key;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static String createJWT(String id, String iss, String subject, long ttlMillis){
        return createJWT(id,iss,subject,ttlMillis,null,null);
    }

    public static String createJWT(String id, String iss, String subject, long ttlMillis,String jwtSecert) {
        return createJWT(id,iss,subject,ttlMillis,jwtSecert,null);
    }
    public static String createJWTByEntity(String id, String iss, String subject, long ttlMillis, String jwtSecert, Object t) {
        try {
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS512;
            long nowMilllis = System.currentTimeMillis();
            Date now = new Date(nowMilllis);
            SecretKey secretKey = generalKey(jwtSecert);
            JwtBuilder builder = Jwts.builder()
                    .setId(id)
                    .setIssuer(iss)
                    .setSubject(subject)
                    .setIssuedAt(now)   //token生成时间
                    .signWith(signatureAlgorithm, secretKey).claim(ENTITY_KEY, t);//设置密匙和算法
            if (ttlMillis > 0) {
                long expMillis = nowMilllis + ttlMillis;
                Date expDate = new Date(expMillis);
                builder.setExpiration(expDate);
            }
            String compact = builder.compact();
            return encryptSelf(compact);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 签发JWT，创建token的方法
     *
     * @param id        jwt的唯一标识，主要用来做一次性token。
     * @param iss       jwt签发者
     * @param subject   jwt所面向的用户。一般使用用户的登录名
     * @param ttlMillis 有效期，单位毫秒
     * @return token 是为一个用户的有效登录周期准备的一个tkoen 。用户推出或超时，token失效
     */
    public static String createJWT(String id, String iss, String subject, long ttlMillis, String jwtSecert, Map map) {
        try {
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS512;
            long nowMilllis = System.currentTimeMillis();
            Date now = new Date(nowMilllis);
            SecretKey secretKey = generalKey(jwtSecert);
            JwtBuilder builder = Jwts.builder()
                    .setId(id)
                    .setIssuer(iss)
                    .setSubject(subject)
                    .setIssuedAt(now)   //token生成时间
                    .signWith(signatureAlgorithm, secretKey);//设置密匙和算法
            if(null != map){
                Set<String> set = map.keySet();
                for (String key : set) {
                    builder.claim(key, map.get(key));
                }
            }

            if (ttlMillis > 0) {
                long expMillis = nowMilllis + ttlMillis;
                Date expDate = new Date(expMillis);
                builder.setExpiration(expDate);
            }
            String compact = builder.compact();
            return encryptSelf(compact);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String encryptSelf(String compact) {
        String[] split = compact.split("\\.");
        String payload = split[1];
        String randomString = RandomGenerator.randomString(2);
        return split[0] + "." + randomString + payload + "." + split[2];
    }
    private static String decryptSelf(String compact) {
        String[] split = compact.split("\\.");
        String payload = split[1];
        return split[0] + "." + payload.substring(2,payload.length()) + "." +split[2];
    }


    public static Claims parseJWT(String jwt) throws Exception{
        return parseJWT(jwt,null);
    }
    /**
     * 解析JWT字符串
     *1
     * @param jwt 就是生成的toekn
     * @return
     * .jsonwebtoken.ExpiredJwtException: JWT expired at 2020-12-29T17:46:14Z. Current time: 2020-12-29T17:46:15Z,
     * a difference of 1920 milliseconds.  Allowed clock skew: 0 milliseconds.
     * io.jsonwebtoken.ExpiredJwtException
     */
    public static Claims parseJWT(String jwt,String jwtSecert) throws Exception{
        SecretKey secretKey = generalKey(jwtSecert);
        jwt = decryptSelf(jwt);
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
    }

    public static String validateJWT(String jwtStr) {
        return validateJWT(jwtStr,null);
    }
    /**
     * 验证jwt
     *
     * @param jwtStr
     * @return
     */
    public static String validateJWT(String jwtStr,String jwtSecert) {
        Claims claims = null;
        try {
            claims = parseJWT(jwtStr,jwtSecert);
            //成功
        } catch (ExpiredJwtException e) {
            //token过期
            e.printStackTrace();
        } catch (SignatureException e) {
            //签名错误
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String generalSubject(Object subject) {
        try {
            return MAPPER.writeValueAsString(subject);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 使用 ——— 生成token
     */
//    public void login() {
//        //生成
//        String jwtToken = JWTUtils.createJWT(UUID.randomUUID().toString(), "test-jwt", JWTUtils.generalSubject("user.getUsername"), 1 * 60 * 1000,null);
//    }


    /**
     * 获取接口放在header中的token
     *
     * @param request
     */
    public void test(HttpServletRequest request) {
        String token = request.getHeader("Authorization");//生成的token
        String result = JWTUtils.validateJWT(token,null);//验证
    }

    public static String createTest() {

        WechatUsers wechatUsers = new WechatUsers();

        wechatUsers.setId(123456L);

        String jwtsecret = "kfds34tyt895499ds@,.osite";
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
//        objectObjectHashMap.put("k1","v1");
//        objectObjectHashMap.put("k2","v2");
        objectObjectHashMap.put("origin", "localhost:8080" + Stringer.SEPARATOR_CAHR +"localhost:8080");
        String jwtToken = JWTUtils.createJWTByEntity(UUID.randomUUID().toString(), "octo",

                "123456"/*JWTUtils.generalSubject("user.getUsername")*/, 100000, jwtsecret, wechatUsers);
        System.out.println(jwtToken);
        return jwtToken;
    }
    public static void main(String[] args) throws Exception {
//        String test11 = MessageFormat.format("userId：{0} ,subjectId：{1} 应该在数据库存在，但是现在没有，请联系相关人员排查原因.", "userId", "subjectId");

//        System.out.println(test11);
        System.out.println(RandomGenerator.randomUUID(false));
        String jwtToken = createTest();
//        String jwtsecret = "kfds34tyt895499ds@,.otest";
        String jwtsecret = "kfds34tyt895499ds@,.osite";

//        String jwtToken ="eyJhbGciOiJIUzUxMiJ9.3keyJqdGkiOiI5NzlmMWI3NS0zMjNhLTQwMmQtOTE0MS0yMzI5ZGQxYWRlN2QiLCJpc3MiOiJBVVRIX0JJRF9HT1YiLCJzdWIiOiJmZjRmMmZhM2RhNjI0YzNiYTMxMjIyMTEyMGNlN2RlMSIsImlhdCI6MTY1ODQ3NDIxOSwiREVQVF9JRCI6IjQ5ZTNhYjEzOTVkMzRlODU5ZDM2MjU2YzhiYzU5NzYxIiwiRE9DS0lOR19TWVNURU1fQ09ERSI6ImVudC1pbmYiLCJFWFBFUlRfSUQiOiIiLCJTVUJKRUNUX1RZUEUiOiIyNTYiLCJMRUdBTF9JRCI6ImZlZmY5MTVlZjU1ODRlMTM5NDE4NWVmYzQyYjRkMmRkIiwiRVhQSVJFX0FUX01JTExJUyI6IjE2NTg0Nzc4MTk4NzMiLCJVU0VSX05BTUUiOiJkZXZfenRzX2NhaV8xIiwiU1VSVkVJTExBTkNFX0RFUFRfTkFNRSI6ImRldl96dHNfY2FpXzHkvIHkuJrkvIHkuJrlkI3np7AiLCJHT1ZfRVhQRVJUX0lEIjoiIiwiTkFNRSI6Inp0cyIsIlNVUlZFSUxMQU5DRV9ERVBUX0NPREUiOiIiLCJTVUJKRUNUX05BTUVTIjoiZGV2X3p0c19jYWlfMeS8geS4muS8geS4muWQjeensCIsIkNBUEFDSVRZX1RZUEUiOiIwIiwiT1JJR0lOIjoiYmlkLWdvdiIsIkxPR0lOX1RZUEUiOiIxIiwiTF9SQU5ET01fU1RSIjoiNWQwZGMwZGM4MTliNDcwNDljOWQwZWIzMjRkZWQ3MmEiLCJFTlRfQURNSU5fRkxBRyI6IjEiLCJTVUJKRUNUX0lEUyI6ImZlZmY5MTVlZjU1ODRlMTM5NDE4NWVmYzQyYjRkMmRkIiwiRVhQSVJFX1RJTUVfTUlMTElTIjoiMzYwMDAwMCIsIlpaSExfQ0FfTE9HSU5fVElEIjoiIiwiZXhwIjoxNjU4NDc3ODE5fQ.Ws8yneTTJZNXjvcrXvpsmrGWW0iTDOr3S3tPDc8zo-sfDFG4oYlv-xhgp1HZF_d4XKjj4ejlwHqIVe-eucRuMg";
//        jwtToken = jwtToken ;
//        TimeUnit.SECONDS.sleep(1);
////        String result = JWTUtils.validateJWT(jwtToken,null);//验证
////        System.out.println("验证结果: \t "+result);

        Claims claims = JWTUtils.parseJWT(jwtToken,jwtsecret);
        Object o = claims.get(ENTITY_KEY);
        HashMap wechatUsers = claims.get(ENTITY_KEY,HashMap.class);
        System.out.println(wechatUsers);
//        long nowold = System.currentTimeMillis();
//
//        System.out.println( (Integer.valueOf((30*60*(1-0.75)) + "")));

//        Long expireTimeMillis = 3000L;
//
//        Long expireAtMillisObj =(nowold + expireTimeMillis);
//
//
//        Long expireAtMillis = Long.valueOf(expireAtMillisObj.toString());
//
//                TimeUnit.MILLISECONDS.sleep(1);
//
//        long nownow = System.currentTimeMillis();
//
//        Long nowLevel = expireAtMillis - nownow;
//
//        BigDecimal top = new BigDecimal(nowLevel);
//        BigDecimal bottom = new BigDecimal(expireTimeMillis);
//
//        BigDecimal waterLevel = top.divide(bottom, 2, RoundingMode.HALF_UP);
////        BigDecimal waterLevel = new BigDecimal("0.76");
//
//        System.out.println("警戒线 {},现有水位 {}" + waterLevel);
//        if(new BigDecimal("0.75").subtract(waterLevel).compareTo(new BigDecimal("0")) > 0){
//
//            System.out.println("超过警戒水位");
//            return;
//        }
//        System.out.println("没有超过警戒水位");

    }

    /**
     * TODO  注意有图片的时候应该和普通参数有区别 ，用到在修改 有人看见记得提醒我
     */
    private void printHeader(HttpServletRequest request) throws IOException {
//		BufferedReader reader = request.getReader();
//		StringBuilder builder = new StringBuilder();
//		String line = reader.readLine();
//		while(line != null){
//			builder.append(line);
//			line = reader.readLine();
//		}
//		reader.close();
//		log.info("header: \t " + builder);
    }

}
